package aer.JuegoConNumeros;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Formatter;
import java.util.Locale;
import java.util.ArrayList;
import java.util.Collections;

public class JuegoConNumeros {
	private static int[] zipi = new int[4];
	private static int[] zape = new int[4];
	private static ArrayList<Integer> a = new ArrayList<Integer>();

	private static In in = new In(new InputStreamReader(System.in));
	private static MarioPrintStream out = new MarioPrintStream(System.out);

	public static void main(String[] args) throws Exception {
		try {
			while (true) {
				a.clear();
				lecturaDatos();
				Collections.sort(a);
				pintarResultado();
			}
		} catch (Exception e) {

		}
	}

	private static void lecturaDatos() throws Exception {
		int primero = in.readInt();
		if (primero == 0) {
			out.llamarFlush();
			throw new Exception();
		}
		zipi[0] = primero;
		contarLineas(primero);

		for (int k = 1; k < 4; k++) {
			zipi[k] = in.readInt();
			contarLineas(zipi[k]);
		}
		for (int k = 0; k < 4; k++) {
			zape[k] = in.readInt();
			contarLineas(zape[k]);
		}
	}

	private static void pintarResultado() {
		int cZipi = 0;
		int cZape = 0;

		int b = 0;
		for (Integer i : a) {
			if (b != i) {
				if ((i & 1) == 1) {
					out.write("Zipi: " + i + "\n");
					cZipi++;
				} else {
					out.write("Zape: " + i + "\n");
					cZape++;
				}
				b = i;
			}
		} // fin for

		out.write("Resultado final: Zipi: " + cZipi + " Zape: " + cZape + "\n");

	} // fin metodo

	private static void contarLineas(int num) {
		int m = 1;

		int longitudNum = calcularLongitud(num);
		int numF = (int) ((int) num + (int) 10000000);

		int longitudActual = calcularLongitud(numF);
		int diferencia = longitudActual - longitudNum;

		for (int j = 0; j < longitudNum; j++) {
			m *= 10;
		}

		for (int i = 0; i < diferencia; i++) {
			a.add((m - num));
			m *= 10;

		} // fin for

	} // fin metodo programa

	private static int calcularLongitud(int num) {
		int acc = 0;
		while (num > 0) {
			num /= (int) 10;
			acc++;
		}
		return acc;
	}

}

class In extends Reader {

	private Reader in;

	private char cb[];
	private int nChars, nextChar;

	private static final int INVALIDATED = -2;
	private static final int UNMARKED = -1;
	private int markedChar = UNMARKED;
	private int readAheadLimit = 0;

	private boolean skipLF = false;

	private boolean markedSkipLF = false;

	private static int defaultCharBufferSize = 8192;
	private static int defaultExpectedLineLength = 80;

	public In(Reader in, int sz) {
		super(in);
		if (sz <= 0)
			throw new IllegalArgumentException("Buffer size <= 0");
		this.in = in;
		cb = new char[sz];
		nextChar = nChars = 0;
	}

	public In(Reader in) {
		this(in, defaultCharBufferSize);
	}

	private void ensureOpen() throws IOException {
		if (in == null)
			throw new IOException("Stream closed");
	}

	private void fill() throws IOException {
		int dst;
		if (markedChar <= UNMARKED) {
			dst = 0;
		} else {
			int delta = nextChar - markedChar;
			if (delta >= readAheadLimit) {
				markedChar = INVALIDATED;
				readAheadLimit = 0;
				dst = 0;
			} else {
				if (readAheadLimit <= cb.length) {
					System.arraycopy(cb, markedChar, cb, 0, delta);
					markedChar = 0;
					dst = delta;
				} else {
					char ncb[] = new char[readAheadLimit];
					System.arraycopy(cb, markedChar, ncb, 0, delta);
					cb = ncb;
					markedChar = 0;
					dst = delta;
				}
				nextChar = nChars = delta;
			}
		}

		int n;
		do {
			n = in.read(cb, dst, cb.length - dst);
		} while (n == 0);
		if (n > 0) {
			nChars = dst + n;
			nextChar = dst;
		}
	}

	public int read() throws IOException {
		synchronized (lock) {
			ensureOpen();
			for (;;) {
				if (nextChar >= nChars) {
					fill();
					if (nextChar >= nChars)
						return -1;
				}
				if (skipLF) {
					skipLF = false;
					if (cb[nextChar] == '\n') {
						nextChar++;
						continue;
					}
				}
				return cb[nextChar++];
			}
		}
	}

	private int read1(char[] cbuf, int off, int len) throws IOException {
		if (nextChar >= nChars) {
			if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
				return in.read(cbuf, off, len);
			}
			fill();
		}
		if (nextChar >= nChars)
			return -1;
		if (skipLF) {
			skipLF = false;
			if (cb[nextChar] == '\n') {
				nextChar++;
				if (nextChar >= nChars)
					fill();
				if (nextChar >= nChars)
					return -1;
			}
		}
		int n = Math.min(len, nChars - nextChar);
		System.arraycopy(cb, nextChar, cbuf, off, n);
		nextChar += n;
		return n;
	}

	public int read(char cbuf[], int off, int len) throws IOException {
		synchronized (lock) {
			ensureOpen();
			if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) {
				throw new IndexOutOfBoundsException();
			} else if (len == 0) {
				return 0;
			}

			int n = read1(cbuf, off, len);
			if (n <= 0)
				return n;
			while ((n < len) && in.ready()) {
				int n1 = read1(cbuf, off + n, len - n);
				if (n1 <= 0)
					break;
				n += n1;
			}
			return n;
		}
	}

	int readInt(boolean ignoreLF) throws IOException {
		StringBuffer s = null;
		int startChar;

		synchronized (lock) {
			ensureOpen();
			boolean omitLF = ignoreLF || skipLF;

			bufferLoop: for (;;) {

				if (nextChar >= nChars)
					fill();
				if (nextChar >= nChars) { /* EOF */
					if (s != null && s.length() > 0)
						return Integer.parseInt(s.toString());
					else
						return 0;
				}
				boolean eol = false;
				char c = 0;
				int i;

				if (omitLF && ((cb[nextChar] == ' ') || (cb[nextChar] == '\n')))
					nextChar++;
				skipLF = false;
				omitLF = false;

				charLoop: for (i = nextChar; i < nChars; i++) {
					c = cb[i];
					if ((c == ' ') || (c == '\r') || (c == '\n')) {
						eol = true;
						break charLoop;
					}
				}

				startChar = nextChar;
				nextChar = i;

				if (eol) {
					String str;
					if (s == null) {
						str = new String(cb, startChar, i - startChar);
					} else {
						s.append(cb, startChar, i - startChar);
						str = s.toString();
					}
					nextChar++;
					if (c == '\r') {
						skipLF = true;
					}
					return Integer.parseInt(str);
				}

				if (s == null)
					s = new StringBuffer(defaultExpectedLineLength);
				s.append(cb, startChar, i - startChar);
			}
		}
	}

	String readToken(boolean ignoreLF) throws IOException {
		StringBuffer s = null;
		int startChar;

		synchronized (lock) {
			ensureOpen();
			boolean omitLF = ignoreLF || skipLF;

			bufferLoop: for (;;) {

				if (nextChar >= nChars)
					fill();
				if (nextChar >= nChars) { /* EOF */
					if (s != null && s.length() > 0)
						return s.toString();
					else
						return null;
				}
				boolean eol = false;
				char c = 0;
				int i;

				if (omitLF && ((cb[nextChar] == ' ') || (cb[nextChar] == '\n')))
					nextChar++;
				skipLF = false;
				omitLF = false;

				charLoop: for (i = nextChar; i < nChars; i++) {
					c = cb[i];
					if ((c == ' ') || (c == '\r') || (c == '\n')) {
						eol = true;
						break charLoop;
					}
				}

				startChar = nextChar;
				nextChar = i;

				if (eol) {
					String str;
					if (s == null) {
						str = new String(cb, startChar, i - startChar);
					} else {
						s.append(cb, startChar, i - startChar);
						str = s.toString();
					}
					nextChar++;
					if (c == '\r') {
						skipLF = true;
					}
					return str;
				}

				if (s == null)
					s = new StringBuffer(defaultExpectedLineLength);
				s.append(cb, startChar, i - startChar);
			}
		}
	}

	String readLine(boolean ignoreLF) throws IOException {
		StringBuffer s = null;
		int startChar;

		synchronized (lock) {
			ensureOpen();
			boolean omitLF = ignoreLF || skipLF;

			bufferLoop: for (;;) {

				if (nextChar >= nChars)
					fill();
				if (nextChar >= nChars) { /* EOF */
					if (s != null && s.length() > 0)
						return s.toString();
					else
						return null;
				}
				boolean eol = false;
				char c = 0;
				int i;

				if (omitLF && (cb[nextChar] == '\n'))
					nextChar++;
				skipLF = false;
				omitLF = false;

				charLoop: for (i = nextChar; i < nChars; i++) {
					c = cb[i];
					if ((c == '\n') || (c == '\r')) {
						eol = true;
						break charLoop;
					}
				}

				startChar = nextChar;
				nextChar = i;

				if (eol) {
					String str;
					if (s == null) {
						str = new String(cb, startChar, i - startChar);
					} else {
						s.append(cb, startChar, i - startChar);
						str = s.toString();
					}
					nextChar++;
					if (c == '\r') {
						skipLF = true;
					}
					return str;
				}

				if (s == null)
					s = new StringBuffer(defaultExpectedLineLength);
				s.append(cb, startChar, i - startChar);
			}
		}
	}

	public String readLine() throws IOException {
		return readLine(false);
	}

	public int readInt() throws IOException {
		return readInt(false);
	}

	public String readToken() throws IOException {
		return readToken(false);
	}

	public long skip(long n) throws IOException {
		if (n < 0L) {
			throw new IllegalArgumentException("skip value is negative");
		}
		synchronized (lock) {
			ensureOpen();
			long r = n;
			while (r > 0) {
				if (nextChar >= nChars)
					fill();
				if (nextChar >= nChars) /* EOF */
					break;
				if (skipLF) {
					skipLF = false;
					if (cb[nextChar] == '\n') {
						nextChar++;
					}
				}
				long d = nChars - nextChar;
				if (r <= d) {
					nextChar += r;
					r = 0;
					break;
				} else {
					r -= d;
					nextChar = nChars;
				}
			}
			return n - r;
		}
	}

	public boolean ready() throws IOException {
		synchronized (lock) {
			ensureOpen();

			if (skipLF) {
				if (nextChar >= nChars && in.ready()) {
					fill();
				}
				if (nextChar < nChars) {
					if (cb[nextChar] == '\n')
						nextChar++;
					skipLF = false;
				}
			}
			return (nextChar < nChars) || in.ready();
		}
	}

	public boolean markSupported() {
		return true;
	}

	public void mark(int readAheadLimit) throws IOException {
		if (readAheadLimit < 0) {
			throw new IllegalArgumentException("Read-ahead limit < 0");
		}
		synchronized (lock) {
			ensureOpen();
			this.readAheadLimit = readAheadLimit;
			markedChar = nextChar;
			markedSkipLF = skipLF;
		}
	}

	public void reset() throws IOException {
		synchronized (lock) {
			ensureOpen();
			if (markedChar < 0)
				throw new IOException((markedChar == INVALIDATED) ? "Mark invalid" : "Stream not marked");
			nextChar = markedChar;
			skipLF = markedSkipLF;
		}
	}

	public void close() throws IOException {
		synchronized (lock) {
			if (in == null)
				return;
			in.close();
			in = null;
			cb = null;
		}
	}
}

class MarioPrintStream extends FilterOutputStream implements Appendable, Closeable {

	public final boolean autoFlush;
	public boolean trouble = false;
	public Formatter formatter;

	/**
	 * Track both the text- and character-output streams, so that their buffers
	 * can be flushed without flushing the entire stream.
	 */
	public MarioBufferedWriter textOut;
	public MarioOutputStreamWriter charOut;

	/**
	 * requireNonNull is explicitly declared here so as not to create an extra
	 * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
	 * early during system initialization.
	 */
	public static <T> T requireNonNull(T obj, String message) {
		if (obj == null)
			throw new NullPointerException(message);
		return obj;
	}

	/**
	 * Returns a charset object for the given charset name.
	 * 
	 * @throws NullPointerException
	 *             is csn is null
	 * @throws UnsupportedEncodingException
	 *             if the charset is not supported
	 */
	public static Charset toCharset(String csn) throws UnsupportedEncodingException {
		requireNonNull(csn, "charsetName");
		try {
			return Charset.forName(csn);
		} catch (IllegalCharsetNameException | UnsupportedCharsetException unused) {
			// UnsupportedEncodingException should be thrown
			throw new UnsupportedEncodingException(csn);
		}
	}

	/* public constructors */
	public MarioPrintStream(boolean autoFlush, OutputStream out) {
		super(out);
		this.autoFlush = autoFlush;
		this.charOut = new MarioOutputStreamWriter(this);
		this.textOut = new MarioBufferedWriter(charOut);
	}

	public MarioPrintStream(boolean autoFlush, OutputStream out, Charset charset) {
		super(out);
		this.autoFlush = autoFlush;
		this.charOut = new MarioOutputStreamWriter(this, charset);
		this.textOut = new MarioBufferedWriter(charOut);
	}

	/*
	 * Variant of the public constructor so that the given charset name can be
	 * verified before evaluating the OutputStream argument. Used by
	 * constructors creating a FileOutputStream that also take a charset name.
	 */
	public MarioPrintStream(boolean autoFlush, Charset charset, OutputStream out) throws UnsupportedEncodingException {
		this(autoFlush, out, charset);
	}

	/**
	 * Creates a new print stream. This stream will not flush automatically.
	 *
	 * @param out
	 *            The output stream to which values and objects will be printed
	 *
	 * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
	 */
	public MarioPrintStream(OutputStream out) {
		this(out, false);
	}

	/**
	 * Creates a new print stream.
	 *
	 * @param out
	 *            The output stream to which values and objects will be printed
	 * @param autoFlush
	 *            A boolean; if true, the output buffer will be flushed whenever
	 *            a byte array is written, one of the <code>println</code>
	 *            methods is invoked, or a newline character or byte (
	 *            <code>'\n'</code>) is written
	 *
	 * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
	 */
	public MarioPrintStream(OutputStream out, boolean autoFlush) {
		this(autoFlush, requireNonNull(out, "Null output stream"));
	}

	/**
	 * Creates a new print stream.
	 *
	 * @param out
	 *            The output stream to which values and objects will be printed
	 * @param autoFlush
	 *            A boolean; if true, the output buffer will be flushed whenever
	 *            a byte array is written, one of the <code>println</code>
	 *            methods is invoked, or a newline character or byte (
	 *            <code>'\n'</code>) is written
	 * @param encoding
	 *            The name of a supported <a
	 *            href="../lang/package-summary.html#charenc"> character
	 *            encoding</a>
	 *
	 * @throws UnsupportedEncodingException
	 *             If the named encoding is not supported
	 *
	 * @since 1.4
	 */
	public MarioPrintStream(OutputStream out, boolean autoFlush, String encoding) throws UnsupportedEncodingException {
		this(autoFlush, requireNonNull(out, "Null output stream"), toCharset(encoding));
	}

	/**
	 * Creates a new print stream, without automatic line flushing, with the
	 * specified file name. This convenience constructor creates the necessary
	 * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, which
	 * will encode characters using the
	 * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
	 * for this instance of the Java virtual machine.
	 *
	 * @param fileName
	 *            The name of the file to use as the destination of this print
	 *            stream. If the file exists, then it will be truncated to zero
	 *            size; otherwise, a new file will be created. The output will
	 *            be written to the file and is buffered.
	 *
	 * @throws FileNotFoundException
	 *             If the given file object does not denote an existing,
	 *             writable regular file and a new regular file of that name
	 *             cannot be created, or if some other error occurs while
	 *             opening or creating the file
	 *
	 * @throws SecurityException
	 *             If a security manager is present and
	 *             {@link SecurityManager#checkWrite checkWrite(fileName)}
	 *             denies write access to the file
	 *
	 * @since 1.5
	 */
	public MarioPrintStream(String fileName) throws FileNotFoundException {
		this(false, new FileOutputStream(fileName));
	}

	/**
	 * Creates a new print stream, without automatic line flushing, with the
	 * specified file name and charset. This convenience constructor creates the
	 * necessary intermediate {@link java.io.OutputStreamWriter
	 * OutputStreamWriter}, which will encode characters using the provided
	 * charset.
	 *
	 * @param fileName
	 *            The name of the file to use as the destination of this print
	 *            stream. If the file exists, then it will be truncated to zero
	 *            size; otherwise, a new file will be created. The output will
	 *            be written to the file and is buffered.
	 *
	 * @param csn
	 *            The name of a supported {@linkplain java.nio.charset.Charset
	 *            charset}
	 *
	 * @throws FileNotFoundException
	 *             If the given file object does not denote an existing,
	 *             writable regular file and a new regular file of that name
	 *             cannot be created, or if some other error occurs while
	 *             opening or creating the file
	 *
	 * @throws SecurityException
	 *             If a security manager is present and
	 *             {@link SecurityManager#checkWrite checkWrite(fileName)}
	 *             denies write access to the file
	 *
	 * @throws UnsupportedEncodingException
	 *             If the named charset is not supported
	 *
	 * @since 1.5
	 */
	public MarioPrintStream(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException {
		// ensure charset is checked before the file is opened
		this(false, toCharset(csn), new FileOutputStream(fileName));
	}

	/**
	 * Creates a new print stream, without automatic line flushing, with the
	 * specified file. This convenience constructor creates the necessary
	 * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, which
	 * will encode characters using the
	 * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
	 * for this instance of the Java virtual machine.
	 *
	 * @param file
	 *            The file to use as the destination of this print stream. If
	 *            the file exists, then it will be truncated to zero size;
	 *            otherwise, a new file will be created. The output will be
	 *            written to the file and is buffered.
	 *
	 * @throws FileNotFoundException
	 *             If the given file object does not denote an existing,
	 *             writable regular file and a new regular file of that name
	 *             cannot be created, or if some other error occurs while
	 *             opening or creating the file
	 *
	 * @throws SecurityException
	 *             If a security manager is present and
	 *             {@link SecurityManager#checkWrite checkWrite(file.getPath())}
	 *             denies write access to the file
	 *
	 * @since 1.5
	 */
	public MarioPrintStream(File file) throws FileNotFoundException {
		this(false, new FileOutputStream(file));
	}

	/**
	 * Creates a new print stream, without automatic line flushing, with the
	 * specified file and charset. This convenience constructor creates the
	 * necessary intermediate {@link java.io.OutputStreamWriter
	 * OutputStreamWriter}, which will encode characters using the provided
	 * charset.
	 *
	 * @param file
	 *            The file to use as the destination of this print stream. If
	 *            the file exists, then it will be truncated to zero size;
	 *            otherwise, a new file will be created. The output will be
	 *            written to the file and is buffered.
	 *
	 * @param csn
	 *            The name of a supported {@linkplain java.nio.charset.Charset
	 *            charset}
	 *
	 * @throws FileNotFoundException
	 *             If the given file object does not denote an existing,
	 *             writable regular file and a new regular file of that name
	 *             cannot be created, or if some other error occurs while
	 *             opening or creating the file
	 *
	 * @throws SecurityException
	 *             If a security manager is present and
	 *             {@link SecurityManager#checkWrite checkWrite(file.getPath())}
	 *             denies write access to the file
	 *
	 * @throws UnsupportedEncodingException
	 *             If the named charset is not supported
	 *
	 * @since 1.5
	 */
	public MarioPrintStream(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException {
		// ensure charset is checked before the file is opened
		this(false, toCharset(csn), new FileOutputStream(file));
	}

	/** Check to make sure that the stream has not been closed */
	public void ensureOpen() throws IOException {
		if (out == null)
			throw new IOException("Stream closed");
	}

	/**
	 * Flushes the stream. This is done by writing any buffered output bytes to
	 * the underlying output stream and then flushing that stream.
	 *
	 * @see java.io.OutputStream#flush()
	 */
	public void flush() {
		synchronized (this) {
			try {
				ensureOpen();
				out.flush();
			} catch (IOException x) {
				trouble = true;
			}
		}
	}

	public boolean closing = false; /* To avoid recursive closing */

	/**
	 * Closes the stream. This is done by flushing the stream and then closing
	 * the underlying output stream.
	 *
	 * @see java.io.OutputStream#close()
	 */
	public void close() {
		synchronized (this) {
			if (!closing) {
				closing = true;
				try {
					textOut.close();
					out.close();
				} catch (IOException x) {
					trouble = true;
				}
				textOut = null;
				charOut = null;
				out = null;
			}
		}
	}

	/**
	 * Flushes the stream and checks its error state. The internal error state
	 * is set to <code>true</code> when the underlying output stream throws an
	 * <code>IOException</code> other than <code>InterruptedIOException</code>,
	 * and when the <code>setError</code> method is invoked. If an operation on
	 * the underlying output stream throws an
	 * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
	 * converts the exception back into an interrupt by doing:
	 * 
	 * <pre>
	 * Thread.currentThread().interrupt();
	 * </pre>
	 * 
	 * or the equivalent.
	 *
	 * @return <code>true</code> if and only if this stream has encountered an
	 *         <code>IOException</code> other than
	 *         <code>InterruptedIOException</code>, or the <code>setError</code>
	 *         method has been invoked
	 */
	public boolean checkError() {
		if (out != null)
			flush();
		if (out instanceof java.io.PrintStream) {
			MarioPrintStream ps = (MarioPrintStream) out;
			return ps.checkError();
		}
		return trouble;
	}

	/**
	 * Sets the error state of the stream to <code>true</code>.
	 *
	 * <p>
	 * This method will cause subsequent invocations of {@link #checkError()} to
	 * return <tt>true</tt> until {@link #clearError()} is invoked.
	 *
	 * @since JDK1.1
	 */
	protected void setError() {
		trouble = true;
	}

	/**
	 * Clears the internal error state of this stream.
	 *
	 * <p>
	 * This method will cause subsequent invocations of {@link #checkError()} to
	 * return <tt>false</tt> until another write operation fails and invokes
	 * {@link #setError()}.
	 *
	 * @since 1.6
	 */
	protected void clearError() {
		trouble = false;
	}

	/*
	 * Exception-catching, synchronized output operations, which also implement
	 * the write() methods of OutputStream
	 */

	/**
	 * Writes the specified byte to this stream. If the byte is a newline and
	 * automatic flushing is enabled then the <code>flush</code> method will be
	 * invoked.
	 *
	 * <p>
	 * Note that the byte is written as given; to write a character that will be
	 * translated according to the platform's default character encoding, use
	 * the <code>print(char)</code> or <code>println(char)</code> methods.
	 *
	 * @param b
	 *            The byte to be written
	 * @see #print(char)
	 * @see #println(char)
	 */
	public void write(int b) {
		try {
			synchronized (this) {
				ensureOpen();
				out.write(b);
				if ((b == '\n') && autoFlush)
					out.flush();
			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
	}

	/**
	 * Writes <code>len</code> bytes from the specified byte array starting at
	 * offset <code>off</code> to this stream. If automatic flushing is enabled
	 * then the <code>flush</code> method will be invoked.
	 *
	 * <p>
	 * Note that the bytes will be written as given; to write characters that
	 * will be translated according to the platform's default character
	 * encoding, use the <code>print(char)</code> or <code>println(char)</code>
	 * methods.
	 *
	 * @param buf
	 *            A byte array
	 * @param off
	 *            Offset from which to start taking bytes
	 * @param len
	 *            Number of bytes to write
	 */
	public void write(byte buf[], int off, int len) {
		try {
			synchronized (this) {
				ensureOpen();
				out.write(buf, off, len);
				if (autoFlush)
					out.flush();
			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
	}

	/*
	 * The following public methods on the text- and character-output streams
	 * always flush the stream buffers, so that writes to the underlying byte
	 * stream occur as promptly as with the original PrintStream.
	 */

	public void write(char buf[]) {
		try {
			synchronized (this) {
				ensureOpen();
				textOut.write(buf);
				textOut.flushBuffer();
				charOut.flushBuffer();
				if (autoFlush) {
					for (int i = 0; i < buf.length; i++)
						if (buf[i] == '\n')
							out.flush();
				}
			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
	}

	public void llamarFlush() throws Exception {
		textOut.flushBuffer();
		charOut.flushBuffer();
		if (autoFlush) {
			out.flush();
		}
	}

	public void write(String s) {
		try {
			synchronized (this) {
				ensureOpen();
				textOut.write(s);

				/*
				 * if (autoFlush && (s.indexOf('\n') >= 0)) { out.flush(); }
				 */

			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
	}

	public void newLine() {
		try {
			synchronized (this) {
				ensureOpen();
				textOut.newLine();
				textOut.flushBuffer();
				charOut.flushBuffer();
				if (autoFlush)
					out.flush();
			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
	}

	/* Methods that do not terminate lines */

	/**
	 * Prints a boolean value. The string produced by <code>{@link
	 * java.lang.String#valueOf(boolean)}</code> is translated into bytes
	 * according to the platform's default character encoding, and these bytes
	 * are written in exactly the manner of the <code>{@link #write(int)}</code>
	 * method.
	 *
	 * @param b
	 *            The <code>boolean</code> to be printed
	 */
	public void print(boolean b) {
		write(b ? "true" : "false");
	}

	/**
	 * Prints a character. The character is translated into one or more bytes
	 * according to the platform's default character encoding, and these bytes
	 * are written in exactly the manner of the <code>{@link #write(int)}</code>
	 * method.
	 *
	 * @param c
	 *            The <code>char</code> to be printed
	 */
	public void print(char c) {
		write(String.valueOf(c));
	}

	/**
	 * Prints an integer. The string produced by <code>{@link
	 * java.lang.String#valueOf(int)}</code> is translated into bytes according
	 * to the platform's default character encoding, and these bytes are written
	 * in exactly the manner of the <code>{@link #write(int)}</code> method.
	 *
	 * @param i
	 *            The <code>int</code> to be printed
	 * @see java.lang.Integer#toString(int)
	 */
	public void print(int i) {
		write(String.valueOf(i));
	}

	/**
	 * Prints a long integer. The string produced by <code>{@link
	 * java.lang.String#valueOf(long)}</code> is translated into bytes according
	 * to the platform's default character encoding, and these bytes are written
	 * in exactly the manner of the <code>{@link #write(int)}</code> method.
	 *
	 * @param l
	 *            The <code>long</code> to be printed
	 * @see java.lang.Long#toString(long)
	 */
	public void print(long l) {
		write(String.valueOf(l));
	}

	/**
	 * Prints a floating-point number. The string produced by <code>{@link
	 * java.lang.String#valueOf(float)}</code> is translated into bytes
	 * according to the platform's default character encoding, and these bytes
	 * are written in exactly the manner of the <code>{@link #write(int)}</code>
	 * method.
	 *
	 * @param f
	 *            The <code>float</code> to be printed
	 * @see java.lang.Float#toString(float)
	 */
	public void print(float f) {
		write(String.valueOf(f));
	}

	/**
	 * Prints a double-precision floating-point number. The string produced by
	 * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
	 * bytes according to the platform's default character encoding, and these
	 * bytes are written in exactly the manner of the <code>{@link
	 * #write(int)}</code> method.
	 *
	 * @param d
	 *            The <code>double</code> to be printed
	 * @see java.lang.Double#toString(double)
	 */
	public void print(double d) {
		write(String.valueOf(d));
	}

	/**
	 * Prints an array of characters. The characters are converted into bytes
	 * according to the platform's default character encoding, and these bytes
	 * are written in exactly the manner of the <code>{@link #write(int)}</code>
	 * method.
	 *
	 * @param s
	 *            The array of chars to be printed
	 *
	 * @throws NullPointerException
	 *             If <code>s</code> is <code>null</code>
	 */
	public void print(char s[]) {
		write(s);
	}

	/**
	 * Prints a string. If the argument is <code>null</code> then the string
	 * <code>"null"</code> is printed. Otherwise, the string's characters are
	 * converted into bytes according to the platform's default character
	 * encoding, and these bytes are written in exactly the manner of the
	 * <code>{@link #write(int)}</code> method.
	 *
	 * @param s
	 *            The <code>String</code> to be printed
	 */
	public void print(String s) {
		if (s == null) {
			s = "null";
		}
		write(s);
	}

	/**
	 * Prints an object. The string produced by the <code>{@link
	 * java.lang.String#valueOf(Object)}</code> method is translated into bytes
	 * according to the platform's default character encoding, and these bytes
	 * are written in exactly the manner of the <code>{@link #write(int)}</code>
	 * method.
	 *
	 * @param obj
	 *            The <code>Object</code> to be printed
	 * @see java.lang.Object#toString()
	 */
	public void print(Object obj) {
		write(String.valueOf(obj));
	}

	/* Methods that do terminate lines */

	/**
	 * Terminates the current line by writing the line separator string. The
	 * line separator string is defined by the system property
	 * <code>line.separator</code>, and is not necessarily a single newline
	 * character (<code>'\n'</code>).
	 */
	public void println() {
		newLine();
	}

	/**
	 * Prints a boolean and then terminate the line. This method behaves as
	 * though it invokes <code>{@link #print(boolean)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>boolean</code> to be printed
	 */
	public void println(boolean x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints a character and then terminate the line. This method behaves as
	 * though it invokes <code>{@link #print(char)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>char</code> to be printed.
	 */
	public void println(char x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints an integer and then terminate the line. This method behaves as
	 * though it invokes <code>{@link #print(int)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>int</code> to be printed.
	 */
	public void println(int x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints a long and then terminate the line. This method behaves as though
	 * it invokes <code>{@link #print(long)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            a The <code>long</code> to be printed.
	 */
	public void println(long x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints a float and then terminate the line. This method behaves as though
	 * it invokes <code>{@link #print(float)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>float</code> to be printed.
	 */
	public void println(float x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints a double and then terminate the line. This method behaves as
	 * though it invokes <code>{@link #print(double)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>double</code> to be printed.
	 */
	public void println(double x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints an array of characters and then terminate the line. This method
	 * behaves as though it invokes <code>{@link #print(char[])}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            an array of chars to print.
	 */
	public void println(char x[]) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints a String and then terminate the line. This method behaves as
	 * though it invokes <code>{@link #print(String)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>String</code> to be printed.
	 */
	public void println(String x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

	/**
	 * Prints an Object and then terminate the line. This method calls at first
	 * String.valueOf(x) to get the printed object's string value, then behaves
	 * as though it invokes <code>{@link #print(String)}</code> and then
	 * <code>{@link #println()}</code>.
	 *
	 * @param x
	 *            The <code>Object</code> to be printed.
	 */
	public void println(Object x) {
		String s = String.valueOf(x);
		synchronized (this) {
			print(s);
			newLine();
		}
	}

	/**
	 * A convenience method to write a formatted string to this output stream
	 * using the specified format string and arguments.
	 *
	 * <p>
	 * An invocation of this method of the form <tt>out.printf(format,
	 * args)</tt> behaves in exactly the same way as the invocation
	 *
	 * <pre>
	 * out.format(format, args)
	 * </pre>
	 *
	 * @param format
	 *            A format string as described in <a
	 *            href="../util/Formatter.html#syntax">Format string syntax</a>
	 *
	 * @param args
	 *            Arguments referenced by the format specifiers in the format
	 *            string. If there are more arguments than format specifiers,
	 *            the extra arguments are ignored. The number of arguments is
	 *            variable and may be zero. The maximum number of arguments is
	 *            limited by the maximum dimension of a Java array as defined by
	 *            <cite>The Java&trade; Virtual Machine Specification</cite>.
	 *            The behaviour on a <tt>null</tt> argument depends on the <a
	 *            href="../util/Formatter.html#syntax">conversion</a>.
	 *
	 * @throws java.util.IllegalFormatException
	 *             If a format string contains an illegal syntax, a format
	 *             specifier that is incompatible with the given arguments,
	 *             insufficient arguments given the format string, or other
	 *             illegal conditions. For specification of all possible
	 *             formatting errors, see the <a
	 *             href="../util/Formatter.html#detail">Details</a> section of
	 *             the formatter class specification.
	 *
	 * @throws NullPointerException
	 *             If the <tt>format</tt> is <tt>null</tt>
	 *
	 * @return This output stream
	 *
	 * @since 1.5
	 */
	public MarioPrintStream printf(String format, Object... args) {
		return format(format, args);
	}

	/**
	 * A convenience method to write a formatted string to this output stream
	 * using the specified format string and arguments.
	 *
	 * <p>
	 * An invocation of this method of the form <tt>out.printf(l, format,
	 * args)</tt> behaves in exactly the same way as the invocation
	 *
	 * <pre>
	 * out.format(l, format, args)
	 * </pre>
	 *
	 * @param l
	 *            The {@linkplain java.util.Locale locale} to apply during
	 *            formatting. If <tt>l</tt> is <tt>null</tt> then no
	 *            localization is applied.
	 *
	 * @param format
	 *            A format string as described in <a
	 *            href="../util/Formatter.html#syntax">Format string syntax</a>
	 *
	 * @param args
	 *            Arguments referenced by the format specifiers in the format
	 *            string. If there are more arguments than format specifiers,
	 *            the extra arguments are ignored. The number of arguments is
	 *            variable and may be zero. The maximum number of arguments is
	 *            limited by the maximum dimension of a Java array as defined by
	 *            <cite>The Java&trade; Virtual Machine Specification</cite>.
	 *            The behaviour on a <tt>null</tt> argument depends on the <a
	 *            href="../util/Formatter.html#syntax">conversion</a>.
	 *
	 * @throws java.util.IllegalFormatException
	 *             If a format string contains an illegal syntax, a format
	 *             specifier that is incompatible with the given arguments,
	 *             insufficient arguments given the format string, or other
	 *             illegal conditions. For specification of all possible
	 *             formatting errors, see the <a
	 *             href="../util/Formatter.html#detail">Details</a> section of
	 *             the formatter class specification.
	 *
	 * @throws NullPointerException
	 *             If the <tt>format</tt> is <tt>null</tt>
	 *
	 * @return This output stream
	 *
	 * @since 1.5
	 */
	public MarioPrintStream printf(Locale l, String format, Object... args) {
		return format(l, format, args);
	}

	/**
	 * Writes a formatted string to this output stream using the specified
	 * format string and arguments.
	 *
	 * <p>
	 * The locale always used is the one returned by
	 * {@link java.util.Locale#getDefault() Locale.getDefault()}, regardless of
	 * any previous invocations of other formatting methods on this object.
	 *
	 * @param format
	 *            A format string as described in <a
	 *            href="../util/Formatter.html#syntax">Format string syntax</a>
	 *
	 * @param args
	 *            Arguments referenced by the format specifiers in the format
	 *            string. If there are more arguments than format specifiers,
	 *            the extra arguments are ignored. The number of arguments is
	 *            variable and may be zero. The maximum number of arguments is
	 *            limited by the maximum dimension of a Java array as defined by
	 *            <cite>The Java&trade; Virtual Machine Specification</cite>.
	 *            The behaviour on a <tt>null</tt> argument depends on the <a
	 *            href="../util/Formatter.html#syntax">conversion</a>.
	 *
	 * @throws java.util.IllegalFormatException
	 *             If a format string contains an illegal syntax, a format
	 *             specifier that is incompatible with the given arguments,
	 *             insufficient arguments given the format string, or other
	 *             illegal conditions. For specification of all possible
	 *             formatting errors, see the <a
	 *             href="../util/Formatter.html#detail">Details</a> section of
	 *             the formatter class specification.
	 *
	 * @throws NullPointerException
	 *             If the <tt>format</tt> is <tt>null</tt>
	 *
	 * @return This output stream
	 *
	 * @since 1.5
	 */
	public MarioPrintStream format(String format, Object... args) {
		try {
			synchronized (this) {
				ensureOpen();
				if ((formatter == null) || (formatter.locale() != Locale.getDefault()))
					formatter = new Formatter((Appendable) this);
				formatter.format(Locale.getDefault(), format, args);
			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
		return this;
	}

	/**
	 * Writes a formatted string to this output stream using the specified
	 * format string and arguments.
	 *
	 * @param l
	 *            The {@linkplain java.util.Locale locale} to apply during
	 *            formatting. If <tt>l</tt> is <tt>null</tt> then no
	 *            localization is applied.
	 *
	 * @param format
	 *            A format string as described in <a
	 *            href="../util/Formatter.html#syntax">Format string syntax</a>
	 *
	 * @param args
	 *            Arguments referenced by the format specifiers in the format
	 *            string. If there are more arguments than format specifiers,
	 *            the extra arguments are ignored. The number of arguments is
	 *            variable and may be zero. The maximum number of arguments is
	 *            limited by the maximum dimension of a Java array as defined by
	 *            <cite>The Java&trade; Virtual Machine Specification</cite>.
	 *            The behaviour on a <tt>null</tt> argument depends on the <a
	 *            href="../util/Formatter.html#syntax">conversion</a>.
	 *
	 * @throws java.util.IllegalFormatException
	 *             If a format string contains an illegal syntax, a format
	 *             specifier that is incompatible with the given arguments,
	 *             insufficient arguments given the format string, or other
	 *             illegal conditions. For specification of all possible
	 *             formatting errors, see the <a
	 *             href="../util/Formatter.html#detail">Details</a> section of
	 *             the formatter class specification.
	 *
	 * @throws NullPointerException
	 *             If the <tt>format</tt> is <tt>null</tt>
	 *
	 * @return This output stream
	 *
	 * @since 1.5
	 */
	public MarioPrintStream format(Locale l, String format, Object... args) {
		try {
			synchronized (this) {
				ensureOpen();
				if ((formatter == null) || (formatter.locale() != l))
					formatter = new Formatter(this, l);
				formatter.format(l, format, args);
			}
		} catch (InterruptedIOException x) {
			Thread.currentThread().interrupt();
		} catch (IOException x) {
			trouble = true;
		}
		return this;
	}

	/**
	 * Appends the specified character sequence to this output stream.
	 *
	 * <p>
	 * An invocation of this method of the form <tt>out.append(csq)</tt> behaves
	 * in exactly the same way as the invocation
	 *
	 * <pre>
	 * out.print(csq.toString())
	 * </pre>
	 *
	 * <p>
	 * Depending on the specification of <tt>toString</tt> for the character
	 * sequence <tt>csq</tt>, the entire sequence may not be appended. For
	 * instance, invoking then <tt>toString</tt> method of a character buffer
	 * will return a subsequence whose content depends upon the buffer's
	 * position and limit.
	 *
	 * @param csq
	 *            The character sequence to append. If <tt>csq</tt> is
	 *            <tt>null</tt>, then the four characters <tt>"null"</tt> are
	 *            appended to this output stream.
	 *
	 * @return This output stream
	 *
	 * @since 1.5
	 */
	public MarioPrintStream append(CharSequence csq) {
		if (csq == null)
			print("null");
		else
			print(csq.toString());
		return this;
	}

	/**
	 * Appends a subsequence of the specified character sequence to this output
	 * stream.
	 *
	 * <p>
	 * An invocation of this method of the form <tt>out.append(csq, start,
	 * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in exactly the
	 * same way as the invocation
	 *
	 * <pre>
	 * out.print(csq.subSequence(start, end).toString())
	 * </pre>
	 *
	 * @param csq
	 *            The character sequence from which a subsequence will be
	 *            appended. If <tt>csq</tt> is <tt>null</tt>, then characters
	 *            will be appended as if <tt>csq</tt> contained the four
	 *            characters <tt>"null"</tt>.
	 *
	 * @param start
	 *            The index of the first character in the subsequence
	 *
	 * @param end
	 *            The index of the character following the last character in the
	 *            subsequence
	 *
	 * @return This output stream
	 *
	 * @throws IndexOutOfBoundsException
	 *             If <tt>start</tt> or <tt>end</tt> are negative,
	 *             <tt>start</tt> is greater than <tt>end</tt>, or <tt>end</tt>
	 *             is greater than <tt>csq.length()</tt>
	 *
	 * @since 1.5
	 */
	public MarioPrintStream append(CharSequence csq, int start, int end) {
		CharSequence cs = (csq == null ? "null" : csq);
		write(cs.subSequence(start, end).toString());
		return this;
	}

	/**
	 * Appends the specified character to this output stream.
	 *
	 * <p>
	 * An invocation of this method of the form <tt>out.append(c)</tt> behaves
	 * in exactly the same way as the invocation
	 *
	 * <pre>
	 * out.print(c)
	 * </pre>
	 *
	 * @param c
	 *            The 16-bit character to append
	 *
	 * @return This output stream
	 *
	 * @since 1.5
	 */
	public MarioPrintStream append(char c) {
		print(c);
		return this;
	}

}

class MarioBufferedWriter extends Writer {

	public Writer out;

	public char cb[];
	public int nChars, nextChar;

	public static int defaultCharBufferSize = 8192;

	/**
	 * Line separator string. This is the value of the line.separator property
	 * at the moment that the stream was created.
	 */
	public String lineSeparator;

	/**
	 * Creates a buffered character-output stream that uses a default-sized
	 * output buffer.
	 *
	 * @param out
	 *            A Writer
	 */
	public MarioBufferedWriter(Writer out) {
		this(out, defaultCharBufferSize);
	}

	/**
	 * Creates a new buffered character-output stream that uses an output buffer
	 * of the given size.
	 *
	 * @param out
	 *            A Writer
	 * @param sz
	 *            Output-buffer size, a positive integer
	 *
	 * @exception IllegalArgumentException
	 *                If {@code sz <= 0}
	 */
	public MarioBufferedWriter(Writer out, int sz) {
		super(out);
		if (sz <= 0)
			throw new IllegalArgumentException("Buffer size <= 0");
		this.out = out;
		cb = new char[sz];
		nChars = sz;
		nextChar = 0;

		// lineSeparator = java.security.AccessController.doPrivileged(
		// new sun.security.action.GetPropertyAction("line.separator"));
	}

	/** Checks to make sure that the stream has not been closed */
	public void ensureOpen() throws IOException {
		if (out == null)
			throw new IOException("Stream closed");
	}

	/**
	 * Flushes the output buffer to the underlying character stream, without
	 * flushing the stream itself. This method is non-public only so that it may
	 * be invoked by PrintStream.
	 */
	void flushBuffer() throws IOException {
		synchronized (lock) {
			ensureOpen();
			if (nextChar == 0)
				return;
			out.write(cb, 0, nextChar);
			nextChar = 0;
		}
	}

	/**
	 * Writes a single character.
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void write(int c) throws IOException {
		synchronized (lock) {
			ensureOpen();
			if (nextChar >= nChars)
				flushBuffer();
			cb[nextChar++] = (char) c;
		}
	}

	/**
	 * Our own little min method, to avoid loading java.lang.Math if we've run
	 * out of file descriptors and we're trying to print a stack trace.
	 */
	public int min(int a, int b) {
		if (a < b)
			return a;
		return b;
	}

	/**
	 * Writes a portion of an array of characters.
	 *
	 * <p>
	 * Ordinarily this method stores characters from the given array into this
	 * stream's buffer, flushing the buffer to the underlying stream as needed.
	 * If the requested length is at least as large as the buffer, however, then
	 * this method will flush the buffer and write the characters directly to
	 * the underlying stream. Thus redundant <code>BufferedWriter</code>s will
	 * not copy data unnecessarily.
	 *
	 * @param cbuf
	 *            A character array
	 * @param off
	 *            Offset from which to start reading characters
	 * @param len
	 *            Number of characters to write
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void write(char cbuf[], int off, int len) throws IOException {
		synchronized (lock) {
			ensureOpen();
			if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) {
				throw new IndexOutOfBoundsException();
			} else if (len == 0) {
				return;
			}

			if (len >= nChars) {
				/*
				 * If the request length exceeds the size of the output buffer,
				 * flush the buffer and then write the data directly. In this
				 * way buffered streams will cascade harmlessly.
				 */
				flushBuffer();
				out.write(cbuf, off, len);
				return;
			}

			int b = off, t = off + len;
			while (b < t) {
				int d = min(nChars - nextChar, t - b);
				System.arraycopy(cbuf, b, cb, nextChar, d);
				b += d;
				nextChar += d;
				if (nextChar >= nChars)
					flushBuffer();
			}
		}
	}

	/**
	 * Writes a portion of a String.
	 *
	 * <p>
	 * If the value of the <tt>len</tt> parameter is negative then no characters
	 * are written. This is contrary to the specification of this method in the
	 * {@linkplain java.io.Writer#write(java.lang.String,int,int) superclass},
	 * which requires that an {@link IndexOutOfBoundsException} be thrown.
	 *
	 * @param s
	 *            String to be written
	 * @param off
	 *            Offset from which to start reading characters
	 * @param len
	 *            Number of characters to be written
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void write(String s, int off, int len) throws IOException {
		synchronized (lock) {
			ensureOpen();

			int b = off, t = off + len;
			while (b < t) {
				int d = min(nChars - nextChar, t - b);
				s.getChars(b, b + d, cb, nextChar);
				b += d;
				nextChar += d;
				if (nextChar >= nChars)
					flushBuffer();
			}
		}
	}

	/**
	 * Writes a line separator. The line separator string is defined by the
	 * system property <tt>line.separator</tt>, and is not necessarily a single
	 * newline ('\n') character.
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void newLine() throws IOException {
		write(lineSeparator);
	}

	/**
	 * Flushes the stream.
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void flush() throws IOException {
		synchronized (lock) {
			flushBuffer();
			out.flush();
		}
	}

	@SuppressWarnings("try")
	public void close() throws IOException {
		synchronized (lock) {
			if (out == null) {
				return;
			}
			try (Writer w = out) {
				flushBuffer();
			} finally {
				out = null;
				cb = null;
			}
		}
	}
}

class MarioOutputStreamWriter extends Writer {

	public final MarioStreamEncoder se;

	/**
	 * Creates an OutputStreamWriter that uses the named charset.
	 *
	 * @param out
	 *            An OutputStream
	 *
	 * @param charsetName
	 *            The name of a supported {@link java.nio.charset.Charset
	 *            charset}
	 *
	 * @exception UnsupportedEncodingException
	 *                If the named encoding is not supported
	 */
	public MarioOutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException {
		super(out);
		if (charsetName == null)
			throw new NullPointerException("charsetName");
		se = MarioStreamEncoder.forOutputStreamWriter(out, this, charsetName);
	}

	/**
	 * Creates an OutputStreamWriter that uses the default character encoding.
	 *
	 * @param out
	 *            An OutputStream
	 */
	public MarioOutputStreamWriter(OutputStream out) {
		super(out);
		try {
			se = MarioStreamEncoder.forOutputStreamWriter(out, this, (String) null);
		} catch (UnsupportedEncodingException e) {
			throw new Error(e);
		}
	}

	/**
	 * Creates an OutputStreamWriter that uses the given charset.
	 *
	 * @param out
	 *            An OutputStream
	 *
	 * @param cs
	 *            A charset
	 *
	 * @since 1.4
	 * @spec JSR-51
	 */
	public MarioOutputStreamWriter(OutputStream out, Charset cs) {
		super(out);
		if (cs == null)
			throw new NullPointerException("charset");
		se = MarioStreamEncoder.forOutputStreamWriter(out, this, cs);
	}

	/**
	 * Creates an OutputStreamWriter that uses the given charset encoder.
	 *
	 * @param out
	 *            An OutputStream
	 *
	 * @param enc
	 *            A charset encoder
	 *
	 * @since 1.4
	 * @spec JSR-51
	 */
	public MarioOutputStreamWriter(OutputStream out, CharsetEncoder enc) {
		super(out);
		if (enc == null)
			throw new NullPointerException("charset encoder");
		se = MarioStreamEncoder.forOutputStreamWriter(out, this, enc);
	}

	/**
	 * Returns the name of the character encoding being used by this stream.
	 *
	 * <p>
	 * If the encoding has an historical name then that name is returned;
	 * otherwise the encoding's canonical name is returned.
	 *
	 * <p>
	 * If this instance was created with the
	 * {@link #OutputStreamWriter(OutputStream, String)} constructor then the
	 * returned name, being unique for the encoding, may differ from the name
	 * passed to the constructor. This method may return <tt>null</tt> if the
	 * stream has been closed.
	 * </p>
	 *
	 * @return The historical name of this encoding, or possibly
	 *         <code>null</code> if the stream has been closed
	 *
	 * @see java.nio.charset.Charset
	 *
	 * @revised 1.4
	 * @spec JSR-51
	 */
	/*
	 * public String getEncoding() { return se.getEncoding(); }
	 */
	/**
	 * Flushes the output buffer to the underlying byte stream, without flushing
	 * the byte stream itself. This method is non-public only so that it may be
	 * invoked by PrintStream.
	 */
	void flushBuffer() throws IOException {
		se.flushBuffer();
	}

	/**
	 * Writes a single character.
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void write(int c) throws IOException {
		se.write(c);
	}

	/**
	 * Writes a portion of an array of characters.
	 *
	 * @param cbuf
	 *            Buffer of characters
	 * @param off
	 *            Offset from which to start writing characters
	 * @param len
	 *            Number of characters to write
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void write(char cbuf[], int off, int len) throws IOException {
		se.write(cbuf, off, len);
	}

	/**
	 * Writes a portion of a string.
	 *
	 * @param str
	 *            A String
	 * @param off
	 *            Offset from which to start writing characters
	 * @param len
	 *            Number of characters to write
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void write(String str, int off, int len) throws IOException {
		se.write(str, off, len);
	}

	/**
	 * Flushes the stream.
	 *
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	public void flush() throws IOException {
		se.flush();
	}

	public void close() throws IOException {
		se.close();
	}
}

class MarioStreamEncoder extends Writer {

	public static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;

	public volatile boolean isOpen = true;

	public void ensureOpen() throws IOException {
		if (!isOpen)
			throw new IOException("Stream closed");
	}

	// Factories for java.io.OutputStreamWriter
	public static MarioStreamEncoder forOutputStreamWriter(OutputStream out, Object lock, String charsetName)
			throws UnsupportedEncodingException {
		String csn = charsetName;
		if (csn == null)
			csn = Charset.defaultCharset().name();
		try {
			if (Charset.isSupported(csn))
				return new MarioStreamEncoder(out, lock, Charset.forName(csn));
		} catch (IllegalCharsetNameException x) {
		}
		throw new UnsupportedEncodingException(csn);
	}

	public static MarioStreamEncoder forOutputStreamWriter(OutputStream out, Object lock, Charset cs) {
		return new MarioStreamEncoder(out, lock, cs);
	}

	public static MarioStreamEncoder forOutputStreamWriter(OutputStream out, Object lock, CharsetEncoder enc) {
		return new MarioStreamEncoder(out, lock, enc);
	}

	// Factory for java.nio.channels.Channels.newWriter

	public static MarioStreamEncoder forEncoder(WritableByteChannel ch, CharsetEncoder enc, int minBufferCap) {
		return new MarioStreamEncoder(ch, enc, minBufferCap);
	}

	// -- Public methods corresponding to those in OutputStreamWriter --

	// All synchronization and state/argument checking is done in these public
	// methods; the concrete stream-encoder subclasses defined below need not
	// do any such checking.
	/*
	 * public String getEncoding() { if (isOpen()) return encodingName(); return
	 * null; }
	 */
	public void flushBuffer() throws IOException {
		synchronized (lock) {
			if (isOpen())
				implFlushBuffer();
			else
				throw new IOException("Stream closed");
		}
	}

	public void write(int c) throws IOException {
		char cbuf[] = new char[1];
		cbuf[0] = (char) c;
		write(cbuf, 0, 1);
	}

	public void write(char cbuf[], int off, int len) throws IOException {
		synchronized (lock) {
			ensureOpen();
			if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) {
				throw new IndexOutOfBoundsException();
			} else if (len == 0) {
				return;
			}
			implWrite(cbuf, off, len);
		}
	}

	public void write(String str, int off, int len) throws IOException {
		/* Check the len before creating a char buffer */
		if (len < 0)
			throw new IndexOutOfBoundsException();
		char cbuf[] = new char[len];
		str.getChars(off, off + len, cbuf, 0);
		write(cbuf, 0, len);
	}

	public void flush() throws IOException {
		synchronized (lock) {
			ensureOpen();
			implFlush();
		}
	}

	public void close() throws IOException {
		synchronized (lock) {
			if (!isOpen)
				return;
			implClose();
			isOpen = false;
		}
	}

	public boolean isOpen() {
		return isOpen;
	}

	// -- Charset-based stream encoder impl --

	public Charset cs;
	public CharsetEncoder encoder;
	public ByteBuffer bb;

	// Exactly one of these is non-null
	public final OutputStream out;
	public WritableByteChannel ch;

	// Leftover first char in a surrogate pair
	public boolean haveLeftoverChar = false;
	public char leftoverChar;
	public CharBuffer lcb = null;

	public MarioStreamEncoder(OutputStream out, Object lock, Charset cs) {
		this(out, lock, cs.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
				.onUnmappableCharacter(CodingErrorAction.REPLACE));
	}

	public MarioStreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
		super(lock);
		this.out = out;
		this.ch = null;
		this.cs = enc.charset();
		this.encoder = enc;

		// This path disabled until direct buffers are faster
		if (false && out instanceof FileOutputStream) {
			ch = ((FileOutputStream) out).getChannel();
			if (ch != null)
				bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
		}
		if (ch == null) {
			bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
		}
	}

	public MarioStreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
		this.out = null;
		this.ch = ch;
		this.cs = enc.charset();
		this.encoder = enc;
		this.bb = ByteBuffer.allocate(mbc < 0 ? DEFAULT_BYTE_BUFFER_SIZE : mbc);
	}

	public void writeBytes() throws IOException {
		bb.flip();
		int lim = bb.limit();
		int pos = bb.position();
		assert (pos <= lim);
		int rem = (pos <= lim ? lim - pos : 0);

		if (rem > 0) {
			if (ch != null) {
				if (ch.write(bb) != rem)
					assert false : rem;
			} else {
				out.write(bb.array(), bb.arrayOffset() + pos, rem);
			}
		}
		bb.clear();
	}

	public void flushLeftoverChar(CharBuffer cb, boolean endOfInput) throws IOException {
		if (!haveLeftoverChar && !endOfInput)
			return;
		if (lcb == null)
			lcb = CharBuffer.allocate(2);
		else
			lcb.clear();
		if (haveLeftoverChar)
			lcb.put(leftoverChar);
		if ((cb != null) && cb.hasRemaining())
			lcb.put(cb.get());
		lcb.flip();
		while (lcb.hasRemaining() || endOfInput) {
			CoderResult cr = encoder.encode(lcb, bb, endOfInput);
			if (cr.isUnderflow()) {
				if (lcb.hasRemaining()) {
					leftoverChar = lcb.get();
					if (cb != null && cb.hasRemaining())
						flushLeftoverChar(cb, endOfInput);
					return;
				}
				break;
			}
			if (cr.isOverflow()) {
				assert bb.position() > 0;
				writeBytes();
				continue;
			}
			cr.throwException();
		}
		haveLeftoverChar = false;
	}

	void implWrite(char cbuf[], int off, int len) throws IOException {
		CharBuffer cb = CharBuffer.wrap(cbuf, off, len);

		if (haveLeftoverChar)
			flushLeftoverChar(cb, false);

		while (cb.hasRemaining()) {
			CoderResult cr = encoder.encode(cb, bb, false);
			if (cr.isUnderflow()) {
				assert (cb.remaining() <= 1) : cb.remaining();
				if (cb.remaining() == 1) {
					haveLeftoverChar = true;
					leftoverChar = cb.get();
				}
				break;
			}
			if (cr.isOverflow()) {
				assert bb.position() > 0;
				writeBytes();
				continue;
			}
			cr.throwException();
		}
	}

	void implFlushBuffer() throws IOException {
		if (bb.position() > 0)
			writeBytes();
	}

	void implFlush() throws IOException {
		implFlushBuffer();
		if (out != null)
			out.flush();
	}

	void implClose() throws IOException {
		flushLeftoverChar(null, true);
		try {
			for (;;) {
				CoderResult cr = encoder.flush(bb);
				if (cr.isUnderflow())
					break;
				if (cr.isOverflow()) {
					assert bb.position() > 0;
					writeBytes();
					continue;
				}
				cr.throwException();
			}

			if (bb.position() > 0)
				writeBytes();
			if (ch != null)
				ch.close();
			else
				out.close();
		} catch (IOException x) {
			encoder.reset();
			throw x;
		}
	}
	/*
	 * String encodingName() { return ((cs instanceof HistoricallyNamedCharset)
	 * ? ((HistoricallyNamedCharset)cs).historicalName() : cs.name()); }
	 */
}
